/**
 * This class will manipulate text in a file with different commands available:
 * {add, display, delete, clear, exit}
 * This class will take in 1 parameter (file name) and the text will be manipulated in the given file name. 
 * Program will react accordingly if arguments are incorrect.
 * Program will react accordingly if any inputs are incorrect.
 * This program will save after every operation.
 * The command format is given by the example give below:
 * 
 * 		c:> TextBuddy mytextfile.txt  (OR c:>java  TextBuddy mytextfile.txt)
 *		Welcome to TextBuddy. mytextfile.txt is ready for use
 *		command: add little brown fox
 *		added to mytextfile.txt: “little brown fox”
 *		command: display
 *		1. little brown fox
 *		command: add jumped over the moon
 *		added to mytextfile.txt: “jumped over the moon”
 *		command: display
 *		1. little brown fox
 *		2. jumped over the moon
 *		command: delete 2
 *		deleted from mytextfile.txt: “jumped over the moon”
 *		command: display
 *		1. little brown fox
 *		command: clear
 *		all content deleted from mytextfile.txt
 *		command: display
 *		mytextfile.txt is empty
 *		command: exit
 *		c:>
 *
 * @author Tan Zheng Jie (Matthew) - A0101810A
 */

import java.util.*;
import java.io.*;

class TextBuddy {
	
	private static final String MESSAGE_WELCOME = "Welcome to TextBuddy. %s is ready for use";
	private static final String MESSAGE_ADDED = "added to my %s: \"%s\"";
	private static final String MESSAGE_DELETED = "deleted from %s: \"%s\"";
	private static final String MESSAGE_EMPTY = "%s is empty";
	private static final String MESSAGE_DISPLAY = "%d. %s";
	private static final String MESSAGE_CLEAR = "all content deleted from %s";
	private static final String MESSAGE_ERROR = "An error has occured, please restart the program";
	private static final String MESSAGE_INVALID_ARGUMENT = "Usage: java TextBuddy <file name>";
	private static final String MESSAGE_INVALID_COMMAND = "Unknown command! Usage: add, delete, display, clear, exit";
	private static final String MESSAGE_INVALID_DELETE = "Invalid number deletion!";
	private static final String MESSAGE_INVALID_DELETE_INPUT = "Usage: delete <number>";
	private static final String MESSAGE_INVALID_ADD = "Usage of add: add <sentence>";
	private static final String MESSAGE_COMMAND = "command:::::::::::::: ";
	
	// These are the possible list of commands
	// replaced enum since switch case works on string from java 7 onwards
	private static final String COMMAND_ADD = "add";
	private static final String COMMAND_DELETE = "delete";
	private static final String COMMAND_DISPLAY = "display";
	private static final String COMMAND_CLEAR = "clear";
	private static final String COMMAND_EXIT = "exit";
	
	
	static String FILE_NAME = "";
	static Scanner scanner = new Scanner(System.in);
	static ArrayList<String> list = new ArrayList<String>();
	
	public static void main(String[] args) {
		checkArguments(args.length);
		checkFile(args[0]);
		showToUser(String.format(MESSAGE_WELCOME, FILE_NAME));
		while(true) {
			String userCommand = readUserCommand();
			String feedback = executeCommand(userCommand);
			showToUser(feedback);
			saveFile();
		}
	}
	
	// Method will check for argument length and exit program if it is not 1
	private static void checkArguments(int argLength) {
		if(argLength != 1) {
			showToUser(MESSAGE_INVALID_ARGUMENT);
			System.exit(0);
		}
	}

	// Create file if file does not exist
	private static void checkFile(String fileName) {
		FILE_NAME = fileName;
		File file = new File(FILE_NAME);
		if(!file.isFile())
			makeFile(file);
		loadFile(file);
	}
	
	// Creates file in the same folder as TextBuddy
	private static void makeFile(File file) {
		try {
			file.createNewFile();
		} catch (IOException e) {
			showToUser(MESSAGE_ERROR);
		}
	}
	
	// Loads file into ArrayList for manipulation
	private static void loadFile(File file) {
		try {
			BufferedReader br = new BufferedReader(new FileReader(file));
			String contentLine = null;
			while((contentLine = br.readLine()) != null) {
				list.add(contentLine);
			}
			br.close();
		} catch (Exception e) {
			showToUser(MESSAGE_ERROR);
		}
	}
	
	// Saves content of ArrayList into file
	private static void saveFile() {
		File file = new File(FILE_NAME);
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(file));
			for(int i = 0; i<list.size(); i++) {
				bw.write(list.get(i));
				bw.newLine();
			}
			bw.close();
		} catch(Exception e) {
			showToUser(MESSAGE_ERROR);
		}
	}
	
	// Method to print messages given different parameters
	private static void showToUser(String message) {
		if(message != null)
			System.out.println(message);
	}
	
	// This method will obtain user's command
	private static String readUserCommand() {
		System.out.print(MESSAGE_COMMAND);
		return scanner.next();
	}

	// Branching method to handle different cases of command
	private static String executeCommand(String userCommand) {
		String feedback = null;
		switch(userCommand) {
			case COMMAND_ADD:
				feedback = executeAdd();
				break;
			case COMMAND_DELETE:
				feedback = executeDelete();
				break;
			case COMMAND_DISPLAY:
				executeDisplay();
				break;
			case COMMAND_CLEAR:
				feedback = executeClear();
				break;
			case COMMAND_EXIT:
				executeExit();
				break;
			default:
				showToUser(MESSAGE_INVALID_COMMAND);
				break;
		}
		return feedback;
	}
	
	// Method to add string input to file
	private static String executeAdd() {
		String inputString = scanner.nextLine().trim();
		if(inputString.length() != 0) {
			list.add(inputString);
		}
		else {
			return MESSAGE_INVALID_ADD;
		}
		return String.format(MESSAGE_ADDED, FILE_NAME, inputString);
	}
	
	// Method to delete sentence from file given index
	private static String executeDelete() {
		if(scanner.hasNextInt() == false) {
			scanner.nextLine(); //buffer for wrong non-integer input
			return MESSAGE_INVALID_DELETE_INPUT;
		}
		int index = scanner.nextInt() - 1;
		if(unableToDelete(index)) {
			return MESSAGE_INVALID_DELETE;
		}
		String deletedString = list.get(index);
		list.remove(index);
		return String.format(MESSAGE_DELETED, FILE_NAME, deletedString);
	}
	
	// Method to check if deletion is possible given an index
	private static boolean unableToDelete(int index) {
		if(index + 1 <= list.size() && list.size() > 0 && index >= 0) {
			return false;
		}
		else {
			return true;
		}
	}
	
	// Method to display all the contents of files
	private static void executeDisplay() {
		if(fileIsEmpty()) {
			showToUser(String.format(MESSAGE_EMPTY, FILE_NAME));
			return;
		}
		for(int i = 1; i <= list.size(); i++) {
			showToUser(String.format(MESSAGE_DISPLAY, i, list.get(i-1)));
		}
	}
	
	// Method to check if file is empty
	private static boolean fileIsEmpty() {
		if(list.isEmpty()) {
			return true;
		}
		else {
			return false;
		}
	}
	
	// Method to erase all contents from the file
	private static String executeClear() {
		list = new ArrayList<String>();
		return String.format(MESSAGE_CLEAR, FILE_NAME);
	}
	
	// Method to exit program given exit command
	private static void executeExit() {
		System.exit(0);
	}

}	